package com.yanqu.road.server.manger.activity.recallplayer;


import com.yanqu.road.entity.activity.ActivityConditionInfo;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.recallplayer.config.RecallPlayerConfig;
import com.yanqu.road.entity.activity.recallplayer.config.RecallPlayerTypeConfig;
import com.yanqu.road.entity.activity.recallplayer.data.RecallPlayerBeBindTaskValue;
import com.yanqu.road.entity.activity.recallplayer.data.UserRecallOtherData;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eRecallPlayerConditionTypeEnum;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.logic.bussiness.activity.RecallPlayerBusiness;
import com.yanqu.road.logic.bussiness.servercenter.ActivityBussiness;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.recallplayer.RecallPlayerModule;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.CommonActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class RecallPlayerMgr extends TempMgr {

    private static ActivityInfo activityInfo;                                               //活动信息
    private static RecallPlayerConfig config;
    private static RandomHelper randomHelper = new RandomHelper();                          //随机

    private static Map<Long, Object> lockMap = new ConcurrentHashMap<>();
    //Map<账号,Map<玩家回归等级,List<回归数据>>>
    private static Map<Long, Map<Integer, List<UserRecallOtherData>>> userRecallOtherMap = new ConcurrentHashMap<>(); //玩家召回其他玩家map
    private static Map<Long, String> userRecallCodeMap = new ConcurrentHashMap<>();                //玩家召回码的map
    private static List<ActivityConditionInfo> allTaskList = new ArrayList<>();

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    @Override
    public boolean save() {
        if (userRecallOtherMap == null || userRecallOtherMap.isEmpty()) {
            return true;
        }
        for (Map<Integer, List<UserRecallOtherData>> userRecallMap : userRecallOtherMap.values()) {
            for (List<UserRecallOtherData> recallList : userRecallMap.values()) {
                for (UserRecallOtherData userRecallOtherData : recallList) {
                    if (userRecallOtherData.isInsertOption()) {
                        RecallPlayerBusiness.addRecallOtherData(userRecallOtherData);
                    } else if (userRecallOtherData.isUpdateOption()) {
                        RecallPlayerBusiness.updateRecallOtherData(userRecallOtherData);
                    }
                }
            }

        }

        return true;
    }

    public static void reloadActivityData() {
        getLogger().info("reload recallPlayer activity start");
        List<ActivityInfo> openActivityInfoList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.RecallPlayerActivity.getValue());
        if (openActivityInfoList.size() <= 0) {
            getLogger().info("reload recallPlayer activity finish, no activity in show time.");
            config = null;
            activityInfo = null;
            return;
        }
        ActivityInfo tempActivityInfo = openActivityInfoList.get(0);

        boolean activityChange = false;
        if (activityInfo == null || activityInfo.getActivityId() != tempActivityInfo.getActivityId()) {
            activityChange = true;
        }

        activityInfo = tempActivityInfo;

        int dayAchieveActive = 100;
        //遍历config查看任务
        eRecallPlayerConditionTypeEnum[] types = eRecallPlayerConditionTypeEnum.values();
        List<ActivityConditionInfo> tmpAllConditionList = new ArrayList<>();
        for (eRecallPlayerConditionTypeEnum type : types) {
            List<ActivityConditionInfo> infoList = NormalActivityMgr.getActivityConditionInfoListByType(RecallPlayerMgr.getActivityInfo().getActivityId(), type.getValue());
            if (infoList != null && !infoList.isEmpty()) {
                tmpAllConditionList.addAll(infoList);
                if (type == eRecallPlayerConditionTypeEnum.activeDuringBack) {
                    //顺便拿个到达活跃度
                    dayAchieveActive = infoList.get(0).getParamList().get(3).intValue();
                }
            }
        }
        allTaskList = tmpAllConditionList;

        List<Integer> activityIdList = new ArrayList<>();
        activityIdList.add(activityInfo.getActivityId());
        //初始化config
        Map<String, ActivityConfig> activityConfigMap = ActivityBussiness.getActivityConfigMap(activityIdList).get(activityInfo.getActivityId());
        RecallPlayerConfig tmpConfig = new RecallPlayerConfig(activityConfigMap);
        tmpConfig.setDayAchieveActive(dayAchieveActive);
        tmpConfig.setDrawConfig(RecallPlayerBusiness.getRecallPlayerDrawConfigMap(activityInfo.getActivityId()));
        tmpConfig.setRecallPlayerTypeConfigList(RecallPlayerBusiness.getRecallPlayerTypeConfigList(activityInfo.getActivityId()));
        config = tmpConfig;

        if (userRecallOtherMap == null || userRecallOtherMap.isEmpty()) {
            userRecallOtherMap = RecallPlayerBusiness.getAllUserRecallOtherInfo();
        }

        if (userRecallCodeMap == null || userRecallCodeMap.isEmpty()) {
            userRecallCodeMap = RecallPlayerBusiness.getUserRecallCodeData();
        }

        for (GamePlayer gamePlayer : GamePlayerMgr.getAllOnlinePlayer()) {
            gamePlayer.getModule(RecallPlayerModule.class).reloadActivityData(activityInfo.getActivityId());
        }

        getLogger().info("reload recallPlayer activity end");

    }

    public static ActivityInfo getActivityInfo() {
        return activityInfo;
    }

    public static Map<Integer, List<UserRecallOtherData>> getUserRecallAllOtherData(long userId) {
        return userRecallOtherMap.get(userId);
    }

    /**
     * 回归玩家发来更新任务
     */

    public static void UpdateBindTask(long returnUserId, long activeUserId, List<RecallPlayerBeBindTaskValue> bindTaskValueList) {
        if (activityInfo == null) {
            return;
        }
        UserRecallOtherData userRecallOtherData = getUserRecallOtherData(activeUserId, returnUserId);
        if (userRecallOtherData == null) {
            return;
        }
        List<RecallPlayerBeBindTaskValue> oldTaskValueList = userRecallOtherData.getTaskData();
        for (RecallPlayerBeBindTaskValue newValue : bindTaskValueList) {
            boolean needAddValue = true;
            for (RecallPlayerBeBindTaskValue oldValue : oldTaskValueList) {
                if (oldValue.getTaskType() == newValue.getTaskType()) {
                    needAddValue = false;
                    oldValue.setTaskValue(newValue.getTaskValue());
                    oldValue.setBindTimeValue(newValue.getBindTimeValue());
                    oldValue.setNeedUpdate(true);
                    userRecallOtherData.setUpdateOption();
                    break;
                }
            }
            if (needAddValue) {
                oldTaskValueList.add(newValue);
            }
            userRecallOtherData.setUpdateOption();
        }
        GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(activeUserId);
        if (onlinePlayer != null) {  //玩家在线的话直接更新一下
            onlinePlayer.getModule(RecallPlayerModule.class).updateTaskList(returnUserId, userRecallOtherData.getPlayerType(), oldTaskValueList);
        }
    }

    /**
     * 获取玩家绑定他人的信息
     *
     * @param userId
     * @param recallUserId
     * @return
     */

    public static UserRecallOtherData getUserRecallOtherData(long userId, long recallUserId) {
        if (userRecallOtherMap.get(userId) == null) {
            userRecallOtherMap.put(userId, new ConcurrentHashMap<>());
        }
        Map<Integer, List<UserRecallOtherData>> recallDataMap = userRecallOtherMap.get(userId);
        for (List<UserRecallOtherData> dataList : recallDataMap.values()) {
            for (UserRecallOtherData userRecallOtherData : dataList) {
                if (userRecallOtherData.getRecallUserId() == recallUserId) {
                    return userRecallOtherData;
                }
            }
        }
        return null;
    }

    /**
     * 添加召回数据
     *
     * @param userRecallOtherData
     */
    public static void addData(UserRecallOtherData userRecallOtherData) {
        synchronized (userRecallOtherMap) {
            long activeUserId = userRecallOtherData.getUserId();
            if (userRecallOtherMap.get(activeUserId) == null) {
                userRecallOtherMap.put(activeUserId, new ConcurrentHashMap<>());
            }
            if (userRecallOtherMap.get(activeUserId).get(userRecallOtherData.getPlayerType()) == null) {
                userRecallOtherMap.get(activeUserId).put(userRecallOtherData.getPlayerType(), new ArrayList<>());
            }
            userRecallOtherMap.get(activeUserId).get(userRecallOtherData.getPlayerType()).add(userRecallOtherData);
        }
    }

    /**
     * 添加用户召回码,用于前来绑定的人判断是否该玩家可以绑定
     */
    public static void addUserRecallCode(long userId, String recallCode) {
        if (StringUtils.isNullOrEmpty(userRecallCodeMap.get(userId))) {
            userRecallCodeMap.put(userId, recallCode);
        }
    }

    /**
     * 查询玩家召回码
     */
    public static String getUserRecallCode(long activeUserId) {
        return userRecallCodeMap.get(activeUserId);
    }


    private static Object getUserLock(long userId) {
        if (!lockMap.containsKey(userId)) {
            synchronized (lockMap) {
                if (!lockMap.containsKey(userId)) {
                    lockMap.put(userId, new Object());
                }
            }
        }
        return lockMap.get(userId);
    }

    public static boolean checkStringAllInDigits(String str) {
        if (str.isEmpty()) {
            return false;
        }
        String digitsStr = String.valueOf(digits);
        char[] chars = str.toCharArray();
        for (char aChar : chars) {
            if (digitsStr.indexOf(aChar) == -1) {
                return false;
            }
        }
        return true;
    }


    /**
     * 商海重逢抄来的 userId生成邀请码
     *
     * @param userId
     * @return
     */
    final static char[] digits = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
            'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E',
            'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };

    /**
     * 召回绑定
     *
     * @param userId
     * @param recallUserId
     * @param userBaseInfo
     * @param recallCode
     */
    public static int recallBind(long userId, long recallUserId, UserBaseInfo userBaseInfo, String recallCode, int recallUserType, List<RecallPlayerBeBindTaskValue> valueList) {
        String cacheRecallCode = getUserRecallCode(userId);
        if (cacheRecallCode == null) {
            return GameErrorCode.E_RECALL_PLAYER_CODE_ERROR; //召回码有误
        }
        if (getActivityInfo() == null) {
            return GameErrorCode.E_RECALL_PLAYER_NO_OPEN;   //活动没开
        }
        if (!Objects.equals(cacheRecallCode, recallCode)) {
            return GameErrorCode.E_RECALL_PLAYER_CODE_ERROR; //召回码有误
        }
        UserRecallOtherData recallUserData = getUserRecallOtherData(userId, recallUserId);
        //汴梁达人活动暂时不重置绑定！
        if (recallUserData != null) {
            return GameErrorCode.E_RECALL_PLAYER_ALREADY_BIND;              //已经填写过
        }
        recallUserData = initUserRecallOtherData(userId, recallUserId, userBaseInfo, recallUserType, valueList);
        synchronized (getUserLock(userId)) {
            if (userRecallOtherMap.get(userId) == null) {
                userRecallOtherMap.put(userId, new ConcurrentHashMap<>());
            }
            Map<Integer, List<UserRecallOtherData>> recallMap = userRecallOtherMap.get(userId);
            if (recallMap.get(recallUserType) == null) {
                recallMap.put(recallUserType, new ArrayList<>());
                recallMap = userRecallOtherMap.get(userId);
            }
            synchronized (recallMap) {
                RecallPlayerTypeConfig recallPlayerTypeConfigByType = config.getRecallPlayerTypeConfigByType(recallUserType);
                if (recallPlayerTypeConfigByType == null) {
                    return GameErrorCode.E_RECALL_PLAYER_TYPE_CONFIG_ERROR;
                }
                int totalNum = 0;
                for (List<UserRecallOtherData> otherDataList:recallMap.values()){
                    totalNum = totalNum + otherDataList.size();
                }

                if (totalNum >= RecallPlayerMgr.getConfig().getRecallPlayerMaxNum()) {
                    return GameErrorCode.E_RECALL_PLAYER_TYPE_MAX_NUM;
                }
                recallMap.get(recallUserType).add(recallUserData);
            }
        }
        GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(userId);
        if (onlinePlayer != null) {
            RecallPlayerModule module = onlinePlayer.getModule(RecallPlayerModule.class);
            module.getRecallUserBaseInfoMap().put(recallUserId, userBaseInfo);
            Map<Integer, List<UserRecallOtherData>> userRecallAllOtherDataMap = userRecallOtherMap.get(userId);
            module.newBindPlayerInit(userRecallAllOtherDataMap);
            module.updateTaskList(recallUserId, recallUserType, valueList);
            module.syncBindOtherData(userRecallAllOtherDataMap);
            module.syncActivityData();
        }
        return 0;
    }

    private static UserRecallOtherData initUserRecallOtherData(long userId, long recallUserId, UserBaseInfo userBaseInfo, int recallUserType, List<RecallPlayerBeBindTaskValue> values) {
        UserRecallOtherData userRecallOtherData = new UserRecallOtherData();
        userRecallOtherData.setUserId(userId);
        userRecallOtherData.setRecallUserId(recallUserId);
        userRecallOtherData.setUserBaseInfo(userBaseInfo);
        userRecallOtherData.setRecallUserServer(userBaseInfo.getServerId());
        userRecallOtherData.setRecallTime(System.currentTimeMillis());
        userRecallOtherData.setPlayerType(recallUserType);
        userRecallOtherData.setTaskData(values);
        userRecallOtherData.setHadInit(false);
        userRecallOtherData.setInsertOption();
        return userRecallOtherData;
    }

    /**
     * 计算玩家属于哪一种掌柜
     *
     * @return
     */
    public static int calculateReturnPlayerType(BigInteger earnSpeed) {
        List<RecallPlayerTypeConfig> recallPlayerTypeConfigList = RecallPlayerMgr.getConfig().getRecallPlayerTypeConfigList();
        int userType = 0;
        for (RecallPlayerTypeConfig recallPlayerTypeConfig : recallPlayerTypeConfigList) {
            if (earnSpeed.compareTo(BigInteger.valueOf(recallPlayerTypeConfig.getScore())) >= 0) {
                userType = recallPlayerTypeConfig.getId();
            } else {
                return userType;
            }
        }
        return userType;
    }

    public static String generateRecallCode(long playerId) {
        return RecallPlayerMgr.tenToSixtyTwoHex(playerId);
    }


    public static String tenToSixtyTwoHex(long value) {
        StringBuilder res = new StringBuilder();
        while (true) {
            int n = (int) (value % digits.length);
            value = (value - n) / digits.length;
            res.append(digits[n]);
            if (value <= 0) {
                break;
            }
        }
        return res.reverse().toString();
    }

    public static long sixtyTwoToTenHex(String value) {
        long res = 0;
        if (!StringUtils.isNullOrEmpty(value)) {
            char[] chars = org.apache.commons.lang.StringUtils.reverse(value).toCharArray();
            for (int i = 0; i < chars.length; i++) {
                int asc = chars[i];
                int n = 0;
                if (asc >= 48 && asc <= 57) { //0-9
                    n = asc - 48; // 0-9
                } else if (asc >= 97 && asc <= 122) { //a-z
                    n = asc - 87; // 10-35
                } else if (asc >= 65 && asc <= 90) { // A-Z
                    n = asc - 29; // 36-61
                }
                res += (long) (Math.pow(digits.length, i) * n);

            }
        }
        return res;
    }

    /**
     * 清除用户数据
     *
     * @param player
     */

    public static void logOutClearData(GamePlayer player) {
        if (!ActivityMgr.activityInShowTime(getActivityInfo())) {
            return;
        }
        if (!SystemOpenMgr.systemOpen(player, eSystemId.Seacraft.getValue())) {
            return;
        }
        if (userRecallOtherMap != null) {
            if (userRecallOtherMap.get(player.getUserId()) != null) {
                for (List<UserRecallOtherData> list : userRecallOtherMap.get(player.getUserId()).values()) {
                    for (UserRecallOtherData recallOtherData : list) {
                        if (recallOtherData.isInsertOption()) {
                            continue;
                        } else {
                            recallOtherData.setUserBaseInfo(null);
                        }
                    }
                }
            }
        }
    }

    public static boolean checkTitle(int titleId) {
        if (titleId >= config.getNeedTitle()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 注册时间开服时间 策划优化说不要了
     * @return
     */

//    public static boolean checkServerOpenServerDays(long registerTime) {
//        if (config == null) {
//            return false;
//        }
//        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
//        if (serverInfo == null) {
//            return false;
//        }
//        long now = System.currentTimeMillis();
//        //开服天数需要>
//        if (DateHelper.calc2DateTDOADays(new Date(serverInfo.getOpenTime() * DateHelper.SECOND_MILLIONS), new Date(now)) < config.getNeedOpenServerDay()) {
//            return false;
//        }
//        //注册时间需要>
//        if ((now - registerTime * DateHelper.SECOND_MILLIONS) < config.getNeedCreateRoleDay() * DateHelper.DAY_MILLIONS) {
//            return false;
//        }
//
//        return true;
//    }

    public static List<ActivityConditionInfo> getAllTaskList() {
        return allTaskList;
    }

    public static ActivityConditionInfo getConditionById(int conditionId) {
        if (allTaskList == null) {
            return null;
        }
        if (allTaskList.isEmpty()) {
            return null;
        }
        for (ActivityConditionInfo activityConditionInfo : allTaskList) {
            if (activityConditionInfo.getConditionId() == conditionId) {
                return activityConditionInfo;
            }
        }
        return null;

    }

    public static RecallPlayerConfig getConfig() {
        return config;
    }

    public static RecallPlayerTypeConfig getRecallTypeConfig(int type) {
        if (config == null) {
            return null;
        }
        for (RecallPlayerTypeConfig recallPlayerTypeConfig : config.getRecallPlayerTypeConfigList()) {
            if (recallPlayerTypeConfig.getId() == type) {
                return recallPlayerTypeConfig;
            }
        }
        return null;
    }

    public static void setConfig(RecallPlayerConfig config) {
        RecallPlayerMgr.config = config;
    }
}
